package com.meshnetics.gb.stack.core;

import com.meshnetics.gb.stack.core.config.StackProfile;
import com.meshnetics.gb.stack.core.apl.ApplicationObject;
import com.meshnetics.gb.stack.core.apl.type.EndPointAddress;
import com.meshnetics.gb.stack.core.event.StackConfirm;
import com.meshnetics.gb.stack.core.event.StackRequest;
import com.meshnetics.gb.stack.core.layer.StackLayer;
import com.meshnetics.gb.event.EventListener;

import java.util.Map;
import java.util.Collection;

/**
 * Base interface for the complete stack.
 *
 * @author mmarkov
 */
public interface Stack {
    /**
     * Returns name of the Stack.
     * @return name of the Stack.
     */
    public String getName();

    /**
     * Returns EventListener of this Stack. There could be system events (including failure ones)
     * and APLRequest-s from application objects
     *
     * @return EventListener of this Stack
     */
    public EventListener getEventListener();

    /**
     * Adds the given EventListener to the list where control events will be relayed.
     *
     * @param listener EventListener to be added to the list
     */
    public void addControlListener(EventListener listener);

    /**
     * Removes the given EventListener frome the list where control events will be relayed.
     *
     * @param listener EventListener to be removed from the list
     */
    public void removeControlListener(EventListener listener);

    /**
     * Returns the list of control listeners for this stack.
     *
     * @return the list of control listeners for this stack
     */
    public Collection getControlListeners();

    /**
     * Starts the Stack.
     */
    public void start();

    /**
     * Stops the Stack.
     */
    public void stop();

    /**
     * Returns top StackLayer of the stack.
     *
     * @return top StackLayer of the stack
     */
    public StackLayer getTopLayer();

    /**
     * Sets StackProfile of the Stack to the given value.
     *
     * @param profile new StackProfile for the stack
     */
    public void setProfile(StackProfile profile);

    /**
     * Returns currently used profile name.
     * @return currently used profile name.
     */
    public String getProfileName();

    /**
     * Executes the given request and returns the resulting confirm.
     *
     * @param req StackRequest to be executed
     * @return resulting StackConfirm
     */
    public StackConfirm execute(StackRequest req);

    /**
     * Executes the given request and returns the resulting confirm but waits no more than the given timeout.
     *
     * @param req StackRequest to be executed
     * @param timeout maximum waiting time in milliseconds
     * @return resulting StackConfirm
     */
    public StackConfirm execute(StackRequest req, long timeout);

    /**
     * Returns an application object mapped to the given endpoint.
     *
     * @param addr endpoint address
     * @return an application object mapped to the given endpoint
     */
    public ApplicationObject getApplicationObject(EndPointAddress addr);

    /**
     * Removes an application object mapped to the given endpoint.
     *
     * @param addr endpoint address
     * @return an application object previously mapped to the given endpoint or null if
     *         the endpoint was not busy
     */
    public ApplicationObject removeApplicationObject(EndPointAddress addr);

    /**
     * Maps the given application object to the given endpoint.
     *
     * @param addr endpoint to map the given application object
     * @param obj application object to be mapped
     */
    public void setApplicationObject(EndPointAddress addr, ApplicationObject obj);

    /**
     * Returns the map containing the list of busy endpoints as a keys and mapped ApplicationObjects
     * as values.
     *
     * @return the map containing the list of busy endpoints as a keys and mapped ApplicationObjects
     *         as values
     */
    public Map getApplicationObjects();
}
